package com.evaluation.kexingcp.psycho.evaluation.sys.utils

import arrow.core.Either
import arrow.core.raise.Raise
import arrow.core.raise.either
import com.evaluation.kexingcp.common.security.util.SecurityUtils
import com.evaluation.kexingcp.psycho.evaluation.sys.controller.vo.EvaluationUserInfo
import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream
import org.springframework.beans.BeanUtils
import org.springframework.transaction.support.TransactionTemplate
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.TimeUnit

fun <A, B> runInTransaction(txTemplate: TransactionTemplate, block: Raise<A>.() -> Either<A, B>): Either<A, B> {
    return txTemplate.execute {
         when (val result = either { block().bind() } ) {
            is Either.Left -> {
                it.setRollbackOnly()
                result
            }

            is Either.Right -> result
        }
    }!!
}

inline fun <T: ExecutorService,R> T.use(block: (T) -> R): R {
    try {
        return block(this);
    } finally {
        this.shutdown()
    }
}

fun Date.toLocalDateTime(): LocalDateTime {
    return LocalDateTime.ofInstant(this.toInstant(), ZoneId.systemDefault())
}

fun LocalDateTime.plus(duration: Long, unit: TimeUnit) : LocalDateTime{
    return when (unit) {
        TimeUnit.DAYS -> this.plusDays(duration)
        TimeUnit.HOURS -> this.plusHours(duration)
        TimeUnit.MINUTES -> this.plusMinutes(duration)
        TimeUnit.SECONDS -> this.plusSeconds(duration)
        TimeUnit.MILLISECONDS -> this.plusNanos(duration * 1000000)
        TimeUnit.MICROSECONDS -> this.plusNanos(duration * 1000)
        TimeUnit.NANOSECONDS -> this.plusNanos(duration)
    }
}

object SpelFunctions {
    @JvmStatic
    fun getIdx(options: BooleanArray, index: Int): Int = if (options[index]) 1 else 0

    @JvmStatic
    fun floor(num: Double): Int = num.toInt()

    @JvmStatic
    fun max(vararg nums: Double): Double = nums.maxWith( Comparator.comparingDouble { it.toDouble() })

    @JvmStatic
    fun getMax(n: Int, vararg numbers: Double): Double {
        // 将可变参数转换为列表，并按降序排序
        val sortedNumbers = numbers.toList().sortedDescending()

        // 返回第 n 大的数
        return sortedNumbers[n - 1]
    }
}

fun getUserInfo() : EvaluationUserInfo {
    val user = SecurityUtils.getUser()
    val res = EvaluationUserInfo()
    BeanUtils.copyProperties(user, res)
    // 获取用户部门层级

    return res
}

fun getUserInfo(userId: Long) : EvaluationUserInfo {
    val user = SecurityUtils.getUser()
    val res = EvaluationUserInfo()
    BeanUtils.copyProperties(user, res)
    // 获取用户部门层级

    return res
}

fun transpose(matrix: MutableList<MutableList<Int>>): MutableList<MutableList<Int>> {
    if (matrix.isEmpty()) return mutableListOf()

    return (0 until matrix[0].size).map { col ->
        matrix.map { row -> row[col] }.toMutableList()
    }.toMutableList()
}